import {
  ConflictException,
  Injectable,
  UnauthorizedException,
  UnprocessableEntityException
} from '@nestjs/common'
import { UsersService } from '../users/users.service'
import { JwtService } from '@nestjs/jwt'
import { User } from '../users/entities/user.entity'
import { LoginDto } from './dto/login.dto'
import { RegisterDto } from './dto/register.dto'
import getRandomNickname, { verifyPassword } from '../common/utils'
import { JwtPayload } from './interfaces/jwt-payload.interface'
import { ProfilesService } from 'src/users/profiles.service'
import { CreateUserDto } from 'src/users/dto/create-user.dto'

@Injectable()
export class AuthService {
  constructor(
    private readonly usersService: UsersService,
    private readonly profilesService: ProfilesService,
    private readonly jwtService: JwtService
  ) {}

  async login(dto: LoginDto): Promise<User> {
    const { mobile, password } = dto

    const user = await this.usersService.findOne({ where: { mobile } })
    if (!user) {
      throw new UnauthorizedException('手机号码或密码错误')
    }

    const isPasswordValid = await verifyPassword(password, user.password)
    if (!isPasswordValid) {
      throw new UnauthorizedException('手机号码或密码错误')
    }

    return user
  }

  async register(dto: RegisterDto): Promise<User> {
    const exist = await this.usersService.findOne({
      where: { mobile: dto.mobile }
    })
    if (exist) {
      throw new ConflictException('手机号已经注册')
    }

    let nickname = dto.nickname ?? ''
    delete dto.nickname

    // 尝试随机生成昵称
    if (!nickname) {
      let retry = 5
      while (retry--) {
        const generated = getRandomNickname()
        const found = await this.profilesService.findOne({
          where: { nickname: generated }
        })
        if (!found) {
          nickname = generated
          break
        }
      }
      if (retry === 0) {
        throw new UnprocessableEntityException('昵称不能为空')
      }
    } else {
      const found = await this.profilesService.findOne({
        where: { nickname }
      })
      if (found) {
        throw new ConflictException('此昵称已被注册')
      }
    }

    const newDto: CreateUserDto = { ...dto, profile: { nickname } }
    return await this.usersService.createOneSimple(newDto)
  }

  signJwt(user: User): string {
    const { mobile, roles } = user
    const payload: JwtPayload = {
      sub: user.id.toString(),
      mobile,
      roles
    }
    return this.jwtService.sign(payload)
  }
}
